from datetime import datetime, timedelta, date
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.http import Http404, HttpResponseRedirect
from django.conf import  settings
from mitems.models import Item, ItemImage, UserProfile, Notification
from mitems.forms import ItemForm, ProfileForm, NotificationForm, FilterForm, GoogleEmail
from django.contrib.auth import logout
from django.utils.encoding import force_unicode
from django.shortcuts import get_object_or_404
import logging
from mitems.tools.utils import facebook_interests, get_search_cookie,\
    get_int, get_live_key, get_google_contacts, convert_timezone, get_timezone_with_ip
from mitems.tools.notify import google_invite_mail, google_invite_web
import operator
from django.core.cache import cache
from django.utils.safestring import mark_safe


log = logging.getLogger(__name__)


def get_dev_items(category=0):
    """Get index items using cache"""
    cache_items = cache.get('dev_items_%s'%category)
    if cache_items:
        return cache_items
    search = dict(created__gte=(datetime.now()-timedelta(seconds=settings.DEV_STORIES_TIME_FRAME)))
    if category:
        search['category__id'] = category
    items = sorted(list(Item.objects.filter(**search).order_by('-score')[:settings.DEV_STORIES_PER_PAGE]),
                       key=operator.attrgetter('created'), reverse=True)
    cache.set('dev_items_%s'%category, items, 120)
    return items


def get_user_activity_rate(person):
    """User activity in 8 last days"""
    positions = []
    for number in range(1, settings.BROADCASTERS_HISTORY):
        day = date.today()-timedelta(days=number)
        last_submit_users = {}
        for user in Item.objects.filter(created__startswith=day).values_list('created_by', flat=True):
            last_submit_users[user] = last_submit_users.get(user, 0) + 1
        last_submit_users = sorted(last_submit_users,
                                   key=last_submit_users.__getitem__, reverse=True)[:settings.BROADCASTERS_AMOUNT]
        try:
            day_percent = ((settings.BROADCASTERS_HISTORY-last_submit_users.index(person))/
                           float(settings.BROADCASTERS_HISTORY))*100
        except ValueError:
            day_percent = settings.BROADCASTERS_DEFAULT_PERCENT
        positions.append(dict(percent=day_percent, date=day))
    return positions


def get_broadcasters():
    """Get broadcasters"""
    cache_broadcasters = cache.get('broadcasters')
    if cache_broadcasters:
        return cache_broadcasters
    search = dict(created__gte=(datetime.now() - timedelta(seconds=settings.BROADCASTERS_TIME_FRAME)),
                  created_by__reputation__gte=settings.MIN_REPUTATION)
    last_submit_users = {}
    for user in Item.objects.filter(**search).values_list('created_by', flat=True):
        last_submit_users[user] = last_submit_users.get(user, 0) + 1
    sorted_last_submit_users = sorted(last_submit_users,
                                      key=last_submit_users.__getitem__,
                                      reverse=True)[:settings.BROADCASTERS_AMOUNT]
    broadcasters = sorted(list(UserProfile.objects.filter(pk__in=sorted_last_submit_users)),
                                key=lambda x: sorted_last_submit_users.index(x.pk))
    for user in broadcasters:
        try:
            day_percent = (((settings.BROADCASTERS_AMOUNT-list(broadcasters).index(user))/
                            float(settings.BROADCASTERS_AMOUNT))*100)
        except ValueError:
            day_percent = settings.BROADCASTERS_DEFAULT_PERCENT
        user.positions = [dict(percent=day_percent, date=date.today())] + get_user_activity_rate(user.id)
    cache.set('broadcasters', broadcasters, 60*60)
    return broadcasters


def get_related_items(item):
    """Get related items using cache"""
    search = {'category__id': item.category_id, 'slumped': False}
    items = list(Item.objects.filter(**search).exclude(pk=item.id).
                 order_by('-score')[:settings.RELATED_STORIES_PER_PAGE])
    return items

def get_index_items():
    """Get index items using cache"""

    cache_items = cache.get('index_items')
    if cache_items:
        return cache_items
    search = dict(slumped=False, time_expired__lte=(datetime.now() + timedelta(seconds=60*8)))
    all_items =Item.objects.filter(**search).order_by('-score', '-time_total')
    rest_items = all_items.count()
    items = all_items[:settings.ITEMS_PER_PAGE]
    if rest_items < settings.ITEMS_PER_PAGE:
        additional_items = Item.objects.filter(slumped=False).\
            exclude(pk__in=[item.pk for item in items]).\
            order_by('-score', '-time_total')[:settings.ITEMS_PER_PAGE-rest_items]
        if additional_items:
            items = sorted(list(items)+list(additional_items),
                           key=operator.attrgetter('score', 'time_total'), reverse=True )
    more_items = True if rest_items > settings.ITEMS_PER_PAGE else False
    for item in items:
        item.opacity = item.item_get_opacity()
        item.airtime_left = item.item_airtime_left()
    items_dict = dict(items=items, more_items=more_items)
    cache.set('index_items', items_dict)
    return items_dict


def get_live_items(search, chapter):
    """Get live items using cache"""
    cache_key = get_live_key(search, chapter)
    if cache_key:
        cache_items = cache.get(cache_key)
        if cache_items:
            return cache_items
    all_items = Item.objects.filter(**search).order_by('-score', '-time_total')
    rest_items = all_items.count()
    items = all_items[:settings.ITEMS_PER_PAGE]
    more_items = True if  rest_items > settings.ITEMS_PER_PAGE else False
    for item in items:
        item.opacity = item.item_get_opacity()
        item.airtime_left = item.item_airtime_left()
    items_dict = dict(items=items, more_items=more_items)
    cache.set(cache_key, items_dict)
    return items_dict


def index(request):
    """Index 8 live"""
    locals().update(get_index_items())
    submit_form = ItemForm()
    main_menu = dict(submit='active')
    chapter = 'submit'
    category = 0
    user_category = 0
    country = 'all'
    dev_items = get_dev_items(category)
    convert_timezone(dev_items, 'created', request.user, request.META.get('REMOTE_ADDR', '127.0.0.1'))
    broadcasters = get_broadcasters()
    return render(request, 'index.html', locals())


def live(request, chapter='8live', category=0, user_category=0, country='all'):
    """Live items"""

    if not chapter in settings.CHAPTERS:
        raise Http404

    category = get_int(category, 0) or get_search_cookie(request, 'category', 0)
    user_category = get_int(user_category, 0) or get_search_cookie(request, 'user_category', 0)
    country = (request.COOKIES.get('country') or 'all') if country == 'all' else country

    search = {'slumped' : False}
    if chapter == 'justin':
        search['created__gte'] = datetime.now()-timedelta(seconds=60*8)
    elif chapter == 'popular':
        pass
    elif chapter == 'slumpin':
        search['time_expired__lte'] = datetime.now()+timedelta(seconds=60*2)
    else:
        search['time_expired__lte'] = datetime.now()+timedelta(seconds=60*8)

    if country != 'all':
        search['location'] = country
    if category:
        search['category__id'] = category
    if user_category and request.user.is_authenticated():
        search['created_by__in'] = request.user.get_follows()

    locals().update(get_live_items(search, chapter))
    main_menu = {'live': 'active' }
    sub_menu = { chapter:'active' }
    form = FilterForm(instance=(request.user if request.user.is_authenticated() else None),
                      country=country)
    dev_items = get_dev_items(category)
    convert_timezone(dev_items, 'created', request.user, request.META.get('REMOTE_ADDR', '127.0.0.1'))
    broadcasters = get_broadcasters()
    return render(request, 'index.html', locals())


@login_required
def welcome(request):
    """ Welcome page for new users without any activity"""
    if request.user.had_activity():
        return HttpResponseRedirect('/')
    profile_user = request.user
    welcome = True
    return render(request, 'welcome.html', locals())


@login_required
def item_upload(request):
    submit_form = ItemForm(request.POST or None)
    if submit_form.is_valid():
        item = submit_form.save(commit=False)
        item.created_by = request.user
        item.updated_by = request.user
        item.location = request.user.location
        item.is_active = True
        item.is_mail = False
        item.save()
        picture_small = request.POST.get('picture_small')
        picture_big = request.POST.get('picture_big')
        if picture_small: ItemImage(image=picture_small, item=item, size='small').save()
        if picture_big: ItemImage(image=picture_big, item=item, size='big').save()
        if request.user.fb_auto_post and 'facebook' in request.user.get_auth_providers():
            try:
                picture = item.get_small_image() or ''
                if picture:
                    picture = picture.get_absolute_url()
                request.graph.me.feed.post(
                    message='',
                    picture=picture,
                    link=item.get_short_url(),
                    name=force_unicode(item.message),
                    description=settings.FACEBOOK_MESSAGE
                )
            except Exception as err:
                log.error('Error facebook share: %s' % err)
        return HttpResponseRedirect('/')
    filename_small = request.POST.get('picture_small')
    filename_big = request.POST.get('picture_big')
    category = 0
    main_menu = dict(submit='active')
    return render(request, 'index.html', locals())


def logout_user(request):
    logout(request)
    return HttpResponseRedirect('/')


def item_view(request, chapter=None, item_slug=None):
    if chapter and chapter not in settings.CHAPTERS or not item_slug:
        raise Http404
    main_menu = {'live': 'active' }
    sub_menu = { chapter: 'active' }
    story = True
    try:
        item = Item.objects.get(slug=item_slug)
    except Item.DoesNotExist:
        absent = True
        sub_menu = { 'popular': 'active' }
        return render(request, 'item_error.html', locals())
#    if item.slumped and not item.is_dev_story() and item.created_by != request.user:
#        slumped = True
#        sub_menu = { 'popular': 'active' }
#        return render(request, 'item_error.html', locals())
    item.airtime_left = item.item_airtime_left()
    all_comments = item.items_comment.count()
    comments = item.items_comment.order_by('-id')[:settings.MAX_RESPONSES]
    more_responses = True if all_comments > settings.MAX_RESPONSES else False
    response_page = 1
    related_items = get_related_items(item)
    return render(request, 'story_item.html', locals())


def user_my_items(request, username, page=1):
    """User's items"""

    try:
        page = int(page)
    except ValueError:
        raise Http404
    profile_user = get_object_or_404(UserProfile, username=username)
    if profile_user == request.user:
        all_items = profile_user.created_by.all()
    else:
        all_items = profile_user.created_by.filter(slumped=False)
    rest_items = all_items.count()
    items = all_items.order_by('slumped', '-score', '-time_total')\
        [settings.ITEMS_PER_PAGE*(page-1):settings.ITEMS_PER_PAGE*page]
    more_items = True if rest_items > settings.ITEMS_PER_PAGE*page else False
    for item in items:
        item.opacity = 1
        item.airtime_left = item.item_airtime_left()
    sub_menu = dict(my_items='active')
    next_page = page+1 if more_items else 0
    prev_page = page-1 if page > 1 else 0
    less_items = True if page > 1 and len(items) else False
    return render(request, 'my_items.html', locals())


@login_required
def user_profile(request):
    """User profile"""
    if not request.user.interest:
        request.user.interest = facebook_interests(request)
    form = ProfileForm(request.POST or None, request.FILES or None, instance=request.user)
    if form.is_valid():
        form.save()
    profile_user = request.user
    sub_menu = dict(profile='active')
    return render(request, 'user_profile.html', locals())


@login_required
def user_notification(request):
    """User notifications"""
    notify = Notification.objects.get_or_create(user=request.user)[0]
    form = NotificationForm(request.POST or None, instance=notify)
    if form.is_valid():
        form.save()
        form = NotificationForm(instance=notify)
    sub_menu = dict(notify='active')
    profile_user = request.user
    messages = request.user.get_notifications()
    return render(request, 'notification.html', locals())


def share_open(request, provider, id):
    if provider not in ('facebook', 'twitter'):
        raise Http404
    return render(request, 'share_open.html', {'id': id, 'provider': provider})

def user_following(request, username, page=1):
    try:
        page = int(page)
    except ValueError:
        raise Http404
    profile_user = get_object_or_404(UserProfile, username=username.lower())
    all_follow = profile_user.get_follows()
    follow = all_follow[settings.FOLLOWS_PER_PAGE*(page-1):settings.FOLLOWS_PER_PAGE*page]
    more_follow = True if len(all_follow) > settings.FOLLOWS_PER_PAGE*page else False
    sub_menu = dict(network='active', following='active')
    next_page = page+1 if more_follow else 0
    prev_page = page-1 if page > 1 else 0
    less_follow = True if page > 1 and len(follow) else False
    return render(request, 'follow.html', locals())

def user_followers(request, username, page=1):
    try:
        page = int(page)
    except ValueError:
        raise Http404
    profile_user = get_object_or_404(UserProfile, username=username.lower())
    all_follow = profile_user.get_followers()
    follow = all_follow[settings.FOLLOWS_PER_PAGE*(page-1):settings.FOLLOWS_PER_PAGE*page]
    more_follow = True if len(all_follow) > settings.FOLLOWS_PER_PAGE*page else False
    sub_menu = dict(network='active', followers='active')
    next_page = page+1 if more_follow else 0
    prev_page = page-1 if page > 1 else 0
    less_follow = True if page > 1 and len(follow) else False
    return render(request, 'follow.html', locals())


def get_contacts(tokens):
    """ Get google email contacts """

    all_contacts = get_google_contacts(*tokens)
    registered_users = UserProfile.objects.filter(is_active=True, is_bot=False,
                                                  email__in=all_contacts.keys()
    )
    for user in registered_users:
        all_contacts.pop(user.email, None)
    new_contacts = []
    for email in all_contacts:
        tpl = ('%s <span class="invite_email_example">%s</span>'.strip() %
               (all_contacts[email] or '', email))
        new_contacts.append((email, mark_safe(tpl)))
    return new_contacts, registered_users


@login_required
def google_contacts(request):
    """Google contacts"""
    tokens = request.user.get_google_tokens()
    if not tokens:
        return HttpResponseRedirect(request.user.get_absolute_url())
    contacts, registered_users = get_contacts(tokens)
    form = GoogleEmail(request.POST or None, choices=contacts,
                       initial={'message': settings.GOOGLE_INVITE_MESSAGE} )
    if form.is_valid():
        emails = form.cleaned_data['emails']
        message = form.cleaned_data['message']
        for email in emails:
            google_invite_mail(request.user, message, [email])
        google_invite_web(request.user, len(emails))
        return HttpResponseRedirect(request.user.get_absolute_url())
    main_menu = {'live': 'active'}
    return render(request, 'google_contacts.html', locals())


def handler500(request):
    """ An error handler which exposes the request object to the error template. """
    from django.template import Context, loader
    from django.http import HttpResponseServerError
    import sys
    error = sys.exc_info()[1]
    context = {'request': request, 'STATIC_URL': settings.STATIC_URL,
               'user': request.user, 'error': error}
    t = loader.get_template('500.html')
    return HttpResponseServerError(t.render(Context(context)))